// Create a new symbol
const mySymbol = Symbol('mySymbol');

// Test the Symbol function
console.log(typeof mySymbol); // Output: symbol

// Test the Symbol.prototype.toString function
var s = mySymbol.toString();
console.log(s); // Output: Symbol(mySymbol)

// Test the Symbol.for function
const globalSymbol = Symbol.for('globalSymbol');
const globalSymbol2 = Symbol.for('globalSymbol');
console.log(globalSymbol === globalSymbol2); // Output: true

// Test the Symbol.keyFor function
var kf = Symbol.keyFor(globalSymbol);
console.log(kf); // Output: globalSymbol

// Test the Symbol.hasInstance function
var s1 = Symbol.hasInstance;
class MyClass {
  static [s1](instance) {
    return typeof instance === 'object';
  }
}

console.log({} instanceof MyClass); // Output: true

// Test the Symbol.isConcatSpreadable function
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
var s2 = Symbol.isConcatSpreadable;
console.log(arr1.concat(arr2)); // Output: [1, 2, 3, [4, 5, 6]]

// Test the Symbol.iterator function
const myObj = {
  [Symbol.iterator]() {
    let i = 0;
    const values = [1, 2, 3];
    return {
      next() {
        if (i >= values.length) {
          return { done: true };
        }
        return { value: values[i++], done: false };
      }
    };
  }
};

for (const value of myObj) {
  console.log(value);
}
// Output:
// 1
// 2
// 3

// Test the Symbol.match function
var s3 = Symbol.match;
class MyMatcher {
  [s3](str) {
    return str.indexOf('hello') !== -1;
  }
}


// Test the Symbol.replace function
class MyReplacer {
  [Symbol.replace](str, newStr) {
    return str.replace(/hello/g, newStr);
  }
}

console.log('hello world'.replace(new MyReplacer(), 'hi')); // Output: 'hi world'

// Test the Symbol.search function
class MySearcher {
  [Symbol.search](str) {
    return str.indexOf('world');
  }
}

console.log('hello world'.search(new MySearcher())); // Output: 6

// Test the Symbol.species function
class MyArray extends Array {
  static get [Symbol.species]() {
    return Array;
  }
}

const myArr = [1,2,3];
const mappedArr = myArr.map(x => x * 2);
console.log(mappedArr instanceof MyArray); // Output: false
console.log(mappedArr instanceof Array); // Output: true

// Test the Symbol.split function
class MySplitter {
  [Symbol.split](str) {
    return str.split(' ');
  }
}

console.log('hello world'.split(new MySplitter())); // Output: ['hello', 'world']

// Test the Symbol.toPrimitive function
const myObj2 = {
  [Symbol.toPrimitive](hint) {
    if (hint === 'number') {
      return 123;
    }
    if (hint === 'string') {
      return 'hello';
    }
    return true;
  }
};

console.log(+myObj2); // Output: 123
console.log(`${myObj2}`); // Output: 'hello'
console.log(myObj2 ? 'truthy' : 'falsy'); // Output: 'truthy'

// Test the Symbol.toStringTag function
class MyClass2 {
  get [Symbol.toStringTag]() {
    return 'MyClass2';
  }
}

const myObj3 = new MyClass2();
console.log(Object.prototype.toString.call(myObj3)); // Output: '[object MyClass2]'
